<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>
<script>
// 摘自掘金博客  参考阮一峰  补充csdn+  百度小程序 
// 人性最大的善  即是不让别人为难 
// 21-04-03 午  阅览红皮书 补充 
// 21-05-19 白  补充修订

//es6引入了Class（类）这个概念。新的class写法让对象原型的写法更加清晰、更像面向对象编程的语法，也更加通俗易懂。
//实际上背后依然使用的 原型和构造函数的概念
//严格模式 不需要使用use strict因为只要代码写在类和模块内，就只能使用严格模式。
//提升class不存在变量提升 (由于继承有关 必须确保子类在父类之后定义)
//类的所有方法都定义在类的prototype属性上面，在类的实例上面调用方法，其实就是调用原型上的方法  原型方法可以通过实例对象调用，但不能通过类名调用，会报错

// class 为es6 用来定义一个类
// 实际上 class只是一个语法糖 是构造函数的另一种写法 
// (语法糖 是一种为避免编码出错 和提高效率编码而生的语法层面的优雅解决方案 简单说 一种便携写法  而已)


// 看代码 
class Person{
}
console.log(typeof Person)                               //funciton
console.log(Person.prototype.constructor === Person)     //true


// 使用看代码 
// 用法和使用 构造函数一样  通过new 来生成对象实例 
class person2 {
}
let json = new person2;


//属性和方法
//定义在constructor 内的属性和方法 即调用在this上 属于实例属性和方法   否则属于原型属性和方法 
class Person {
  constructor (name) {
    this.name = name            //constructor内定义的方法和属性是实例对象自己的，
  }
  say () {                      //而constructor外定义的方法和属性则是所有实例对象可以共享的 注意!
    console.log('hello')
  }
}
let jon = new Person()
jon.hasOwnPrototype('name')     //true
jon.hasOwnPrototype('say')      //false



//静态方法  
//不需要通过实例对象，可以直接通过类来调用的方法，其中的 this 指向类本身  
class Person {
  static doSay () {
    this.say()
  }
  static say () {
    console.log('hello')
  }
}
Person.doSay()              //hello

//静态方法可以被子类继承
class Sub extends Person { 
}
Sub.doSay() // hello

//静态方法可以通过类名调用，不能通过实例对象调用，否则会报错
class Person {
    static sum(a, b) {
        console.log(a + b)
    }
}
var p = new Person()
Person.sum(1, 2)  // 3
p.sum(1,2)        //  TypeError p.sum is not a function






//name 属性
//name 属性返回了类的名字 即紧跟在class后面的名字。
class Person {
}
Person.name // Person


//this 默认指向类的实例。
//类的方法内部如果含有this 坑儿 一但单独使用该方法 很可能就会报错 
//如果 this指向不对 1使用箭头函数 2在构造方法中绑定this 




//取值函数（getter）和存值函数（setter）
class Person {
  get name () {
    return 'getter'
  }
  set name(val) {
    console.log('setter' + val)
  }
}

let jon = new Person()
jon.name = 'jon' // setter jon
jon.name         // getter




//calss 表达式 
// 如果需要，可为类定义一个类内部名字，如果不需要，可以省略：
// 需要在类内部使用类名
const Person = class Obj {
  getClassName () {
    return Obj.name
  }
}
// 不需要
const Person = class {}




// 立即执行的 Class：
let jon = new class {
  constructor(name) {
    this.name = name
  }
  sayName() {
    console.log(this.name)
  }
}('jon')
jon.sayName() //jon




//类声明不可以重复
class Person {}
class Person {}
// TypeError Identifier 'Person' has already been declared
















</script>